package com.hyper_yang._05_juc.chap01;

import java.util.concurrent.TimeUnit;

//资源类
class Phone{
    public static synchronized void sendSms(){
        //sleep()不释放锁。
        try {TimeUnit.MILLISECONDS.sleep(4000);} catch (InterruptedException e) {e.printStackTrace();}
        System.out.println(Thread.currentThread().getName()+ " sendSms");
    }

    public synchronized void sendEmail(){
        System.out.println(Thread.currentThread().getName()+ " sendEmail");
    }

    public void hello(){
        System.out.println(Thread.currentThread().getName()+ " hello");
    }
}

/**
 * 讨论：锁是谁？
 * 使用锁的8种情况。
 *
 * 看下面这段儿代码，回答多线程的8个问题：
 *
 * 1. 先访问短信，再访问邮件，先打印短信还是邮件
 *  A sendSms
 *  B sendEmail
 *  虽然多个线程启动后，执行没有先后顺序，但是，A线程先start，具备一定优势。所以，先获取当前对象的锁(this)，先打印发短信，后打印发邮件。
 *
 * 2. 停4秒在短信方法内，先打印短信还是邮件
 * A sendSms
 * B sendEmail
 * 虽然多个线程启动后，执行没有先后顺序，但是，A线程先start，具备一定优势。A线程获取到了当前对象的锁(this) 睡觉，睡醒后打印发短信，然后释放锁，被B线程获取再打印发邮件。。
 *
 * 3. 先访问短信，再访问hello方法，是先打短信还是hello
 *  B hello
 *  A sendSms
 *  A线程获取this对象锁，但是睡觉，而B线程打印hello不需要获取锁，不用等，所以：会先打印hello,后打印sendSms
 *
 * 4. 现在有两部手机，第一部发短信，第二部发邮件，先打印短信还是邮件
 *  B sendEmail
 *  A sendSms
 *  两个手机对象，两把锁， A和B线程各用一把锁。互不影响。由于A线程先启动具有先天优势，但是睡觉。所以，先打印邮件，再打印短信。
 *
 * 5. 两个静态同步方法，1部手机，先打印短信还是邮件
 *  A sendSms
 *  B sendEmail
 *  静态同步方法调用，不依赖于对象，而是依赖于类(可以通过类名调用Phone.sendSms())。
 *      所以抢锁，抢的是Phone类的Class对象的锁。
 *
 * 6. 两个静态同步方法，2部手机，先打印短信还是邮件
 *    A sendSms
 *    B sendEmail
 *  与几部手机无关，与Phone类的Class对象的锁有关。大家都是抢类对象的锁。
 *
 * 7. 1个静态同步方法，1个普通同步方法，1部手机，先打印短信还是邮件
 *  B hello
 *  A sendSms
 *
 *  A抢Class对象锁。hello不需要抢锁。
 *
 * 8. 1个静态同步方法，1个普通同步方法，2部手机，先打印短信还是邮件
 * B sendEmail
 * A sendSms
 * A抢Class对象锁；B抢phone2对象的锁；  各用各的锁。不冲突。
 */
public class Lock8 {
    public static void main(String[] args) {
        Phone phone = new Phone(); //每个对象都有一把锁。锁就是对象头中一个整数值标记：0表示锁没有人使用。大于0表示锁被使用。
        Phone phone2 = new Phone();
        new Thread(()->{
            phone.sendSms();
            //Phone.sendSms(); //抢的是Class clazz = Phone.class  对象的锁。
        },"A").start();

        new Thread(()->{
            //phone.sendEmail();
            //Phone.sendEmail(); //抢的是Class clazz = Phone.class  对象的锁。
            phone2.sendEmail();
            //phone.hello();
        },"B").start();

    }
}
